package com.micro.ai.models.service.impl;

import com.micro.ai.models.entity.DatasetRecord;
import com.micro.ai.models.entity.ModelConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 模型评估执行器
 * 负责运行模型评估任务，计算评估指标
 * 
 * 说明：
 * 1. 实际实现需要集成LLM API客户端（如OpenAI、Anthropic等）
 * 2. 或调用本地部署的模型服务
 * 3. 根据评估类型选择合适的评估指标
 * 
 * @author micro-ai
 * @since 0.0.1
 */
@Slf4j
@Component
public class ModelEvaluationExecutor {

    /**
     * 运行模型评估
     * 
     * @param modelConfig 模型配置
     * @param testRecords 测试数据集记录
     * @param evaluationType 评估类型（exact_match, contains, semantic_similarity, bleu等）
     * @return 评估结果
     */
    public EvaluationResult runEvaluation(ModelConfig modelConfig, 
                                          List<DatasetRecord> testRecords,
                                          String evaluationType) {
        EvaluationResult result = new EvaluationResult();
        List<SingleEvaluationResult> singleResults = new ArrayList<>();
        
        int correctCount = 0;
        int totalCount = testRecords.size();
        double totalScore = 0.0;
        
        for (DatasetRecord record : testRecords) {
            try {
                // 1. 调用模型API获取输出
                String modelOutput = callModelAPI(modelConfig, record.getInputText());
                
                // 2. 计算单个样本的评估结果
                SingleEvaluationResult singleResult = evaluateSingle(
                    record.getInputText(),
                    record.getOutputText(), // 期望输出
                    modelOutput, // 实际输出
                    evaluationType
                );
                
                singleResults.add(singleResult);
                
                if (singleResult.isCorrect()) {
                    correctCount++;
                }
                totalScore += singleResult.getScore();
                
            } catch (Exception e) {
                log.error("评估样本失败: recordId={}, error={}", record.getId(), e.getMessage());
                // 记录错误的样本，但不中断整个评估
                SingleEvaluationResult errorResult = new SingleEvaluationResult();
                errorResult.setInput(record.getInputText());
                errorResult.setExpected(record.getOutputText());
                errorResult.setActual("ERROR: " + e.getMessage());
                errorResult.setCorrect(false);
                errorResult.setScore(0.0);
                singleResults.add(errorResult);
            }
        }
        
        // 计算总体指标
        double accuracy = totalCount > 0 ? (double) correctCount / totalCount : 0.0;
        double avgScore = totalCount > 0 ? totalScore / totalCount : 0.0;
        
        result.setOverallScore(avgScore);
        
        Map<String, Object> metrics = new HashMap<>();
        metrics.put("accuracy", accuracy);
        metrics.put("total_samples", totalCount);
        metrics.put("correct_samples", correctCount);
        metrics.put("average_score", avgScore);
        
        // 根据评估类型添加特定指标
        if ("bleu".equalsIgnoreCase(evaluationType) || "text_generation".equalsIgnoreCase(evaluationType)) {
            double bleuScore = calculateBLEUScore(singleResults);
            metrics.put("bleu_score", bleuScore);
        }
        
        if ("semantic_similarity".equalsIgnoreCase(evaluationType)) {
            double avgSimilarity = singleResults.stream()
                .mapToDouble(SingleEvaluationResult::getScore)
                .average()
                .orElse(0.0);
            metrics.put("average_similarity", avgSimilarity);
        }
        
        result.setMetrics(metrics);
        result.setDetailedResults(singleResults);
        
        log.info("评估完成: total={}, correct={}, accuracy={}, avgScore={}", 
                totalCount, correctCount, accuracy, avgScore);
        
        return result;
    }

    /**
     * 调用模型API
     * 
     * 实际实现需要：
     * 1. 根据modelConfig中的配置（API地址、密钥等）调用相应的LLM API
     * 2. 或调用本地模型服务
     */
    private String callModelAPI(ModelConfig modelConfig, String input) {
        // 方案1: 调用OpenAI API
        /*
        OpenAIAPIClient client = new OpenAIAPIClient(modelConfig.getApiKeyEncrypted());
        ChatCompletionRequest request = new ChatCompletionRequest();
        request.setModel(modelConfig.getModelId());
        request.setMessages(Arrays.asList(
            new ChatMessage("user", input)
        ));
        ChatCompletionResponse response = client.createChatCompletion(request);
        return response.getChoices().get(0).getMessage().getContent();
        */
        
        // 方案2: 调用本地模型服务
        /*
        String apiUrl = modelConfig.getApiBaseUrl() + "/v1/chat/completions";
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(apiUrl))
            .header("Authorization", "Bearer " + modelConfig.getApiKeyEncrypted())
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(
                JSON.toJSONString(Map.of("messages", 
                    List.of(Map.of("role", "user", "content", input)))
                ))
            ))
            .build();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        // 解析响应
        return parseResponse(response.body());
        */
        
        // 当前为示例实现
        log.warn("模型API客户端未实现，返回模拟结果");
        return "模拟输出: " + input;
    }

    /**
     * 评估单个样本
     */
    private SingleEvaluationResult evaluateSingle(String input, String expected, 
                                                   String actual, String evaluationType) {
        SingleEvaluationResult result = new SingleEvaluationResult();
        result.setInput(input);
        result.setExpected(expected);
        result.setActual(actual);
        
        if (!StringUtils.hasText(expected) || !StringUtils.hasText(actual)) {
            result.setCorrect(false);
            result.setScore(0.0);
            return result;
        }
        
        switch (evaluationType.toLowerCase()) {
            case "exact_match":
                // 精确匹配
                boolean exactMatch = expected.trim().equalsIgnoreCase(actual.trim());
                result.setCorrect(exactMatch);
                result.setScore(exactMatch ? 1.0 : 0.0);
                break;
                
            case "contains":
                // 包含关系
                boolean contains = actual.toLowerCase().contains(expected.toLowerCase());
                result.setCorrect(contains);
                result.setScore(contains ? 1.0 : 0.0);
                break;
                
            case "semantic_similarity":
                // 语义相似度（需要使用embedding模型）
                double similarity = calculateSemanticSimilarity(expected, actual);
                result.setScore(similarity);
                result.setCorrect(similarity > 0.8); // 阈值可配置
                break;
                
            case "bleu":
            case "text_generation":
                // BLEU分数
                double bleu = computeBLEUScore(expected, actual);
                result.setScore(bleu);
                result.setCorrect(bleu > 0.3); // BLEU阈值可配置
                break;
                
            default:
                // 默认使用包含关系
                boolean defaultContains = actual.toLowerCase().contains(expected.toLowerCase());
                result.setCorrect(defaultContains);
                result.setScore(defaultContains ? 1.0 : 0.0);
        }
        
        return result;
    }

    /**
     * 计算BLEU分数
     * 
     * 注意：实际实现需要使用BLEU计算库，如：
     * - Java: 使用外部Python服务或JNI调用
     * - 或使用简化的BLEU算法
     */
    private double computeBLEUScore(String reference, String candidate) {
        // 简化版BLEU计算（实际应该使用标准BLEU算法）
        // 这里使用简单的n-gram重叠率作为示例
        
        String[] refWords = reference.toLowerCase().split("\\s+");
        String[] candWords = candidate.toLowerCase().split("\\s+");
        
        if (refWords.length == 0 || candWords.length == 0) {
            return 0.0;
        }
        
        // 计算1-gram精确率
        int matches = 0;
        for (String candWord : candWords) {
            for (String refWord : refWords) {
                if (candWord.equals(refWord)) {
                    matches++;
                    break;
                }
            }
        }
        
        double precision = (double) matches / candWords.length;
        
        // 简化的BLEU = 精确率 * 长度惩罚
        double brevityPenalty = Math.min(1.0, (double) candWords.length / refWords.length);
        
        return precision * brevityPenalty;
    }

    /**
     * 计算语义相似度
     * 
     * 需要：
     * 1. 使用embedding模型将文本转换为向量
     * 2. 计算余弦相似度
     */
    private double calculateSemanticSimilarity(String text1, String text2) {
        // TODO: 实现语义相似度计算
        // 方案1: 调用embedding API（如OpenAI embeddings）
        // 方案2: 使用本地embedding模型
        // 方案3: 使用简化的字符串相似度算法
        
        // 当前使用简化的字符串相似度
        return calculateStringSimilarity(text1, text2);
    }

    /**
     * 计算字符串相似度（简化版）
     */
    private double calculateStringSimilarity(String s1, String s2) {
        if (s1 == null || s2 == null) {
            return 0.0;
        }
        
        // 使用Levenshtein距离的简化版本
        int maxLen = Math.max(s1.length(), s2.length());
        if (maxLen == 0) {
            return 1.0;
        }
        
        int distance = levenshteinDistance(s1, s2);
        return 1.0 - (double) distance / maxLen;
    }

    /**
     * Levenshtein距离（编辑距离）
     */
    private int levenshteinDistance(String s1, String s2) {
        int[][] dp = new int[s1.length() + 1][s2.length() + 1];
        
        for (int i = 0; i <= s1.length(); i++) {
            dp[i][0] = i;
        }
        for (int j = 0; j <= s2.length(); j++) {
            dp[0][j] = j;
        }
        
        for (int i = 1; i <= s1.length(); i++) {
            for (int j = 1; j <= s2.length(); j++) {
                if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = Math.min(
                        Math.min(dp[i - 1][j], dp[i][j - 1]),
                        dp[i - 1][j - 1]
                    ) + 1;
                }
            }
        }
        
        return dp[s1.length()][s2.length()];
    }

    /**
     * 计算整体BLEU分数
     */
    private double calculateBLEUScore(List<SingleEvaluationResult> results) {
        double totalBLEU = results.stream()
            .mapToDouble(SingleEvaluationResult::getScore)
            .average()
            .orElse(0.0);
        
        return totalBLEU;
    }

    /**
     * 评估结果
     */
    public static class EvaluationResult {
        private Double overallScore;
        private Map<String, Object> metrics;
        private List<SingleEvaluationResult> detailedResults;

        public Double getOverallScore() {
            return overallScore;
        }

        public void setOverallScore(Double overallScore) {
            this.overallScore = overallScore;
        }

        public Map<String, Object> getMetrics() {
            return metrics;
        }

        public void setMetrics(Map<String, Object> metrics) {
            this.metrics = metrics;
        }

        public List<SingleEvaluationResult> getDetailedResults() {
            return detailedResults;
        }

        public void setDetailedResults(List<SingleEvaluationResult> detailedResults) {
            this.detailedResults = detailedResults;
        }
    }

    /**
     * 单个样本评估结果
     */
    public static class SingleEvaluationResult {
        private String input;
        private String expected;
        private String actual;
        private Boolean correct;
        private Double score;

        public String getInput() {
            return input;
        }

        public void setInput(String input) {
            this.input = input;
        }

        public String getExpected() {
            return expected;
        }

        public void setExpected(String expected) {
            this.expected = expected;
        }

        public String getActual() {
            return actual;
        }

        public void setActual(String actual) {
            this.actual = actual;
        }

        public Boolean isCorrect() {
            return correct;
        }

        public void setCorrect(Boolean correct) {
            this.correct = correct;
        }

        public Double getScore() {
            return score;
        }

        public void setScore(Double score) {
            this.score = score;
        }
    }
}

